using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace System.Xml
{

	/// <summary>The XmlSerializationExtensions class</summary>
	/// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
	public static class XmlSerializationExtensions
	{
		/// <summary>Converts the object to a binary array by serializing.</summary>
		/// <typeparam name="T">The type of item.</typeparam>
		/// <param name="item">The object to convert.</param>
		/// <returns>A serialized binary array of the object.</returns>
		/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 01:42:59 GMT"/>
		public static byte[] ToBinary<T>(this T item)
		{
			if (item == null)
				return null;

			var serializer = new DataContractSerializer(typeof(T));

			byte[] buffer;
			using (var ms = new MemoryStream())
			using (var writer = XmlDictionaryWriter.CreateBinaryWriter(ms))
			{
				serializer.WriteObject(writer, item);
				writer.Flush();
				buffer = ms.ToArray();
			}

			return buffer;
		}

		/// <summary>Deserializes an instance of T from a byte array.</summary>
		/// <param name="buffer">The byte array representing a T instance.</param>
		/// <returns>An instance of T that is deserialized from the byte array.</returns>
		/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 01:42:59 GMT"/>
		public static T ToObject<T>(this byte[] buffer)
		{
			var deserializer = new DataContractSerializer(typeof(T));

			using (var ms = new MemoryStream(buffer))
			using (var reader = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max))
			{
				return (T)deserializer.ReadObject(reader);
			}
		}

		/// <summary>Returns an XML <see cref="T:System.String"/>that represents the current <see cref="T:System.Object"/>.</summary>
		/// <returns>An XML <see cref="T:System.String"/>that represents the current <see cref="T:System.Object"/>.</returns>
		/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 01:42:59 GMT"/>
		public static string ToXmlString<T>(this T item)
		{
			var settings = new XmlWriterSettings();
			settings.Indent = true;
			settings.OmitXmlDeclaration = true;
			
			var sb = new System.Text.StringBuilder();
			using (var writer = XmlWriter.Create(sb, settings))
			{
				var serializer = new DataContractSerializer(typeof(T));
				serializer.WriteObject(writer, item);
			}

			return sb.ToString();
		}
		/// <summary>Returns an XML <see cref="T:XElement"/>that represents the current <typeparamref name="T"/>.</summary>
		/// <returns>An XML <see cref="T:XElement"/>that represents the current <typeparamref name="T"/>.</returns>
		/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 01:42:59 GMT"/>
		public static XElement ToXElement<T>(this T item, LoadOptions loadOptions = LoadOptions.None)
		{
			return XElement.Parse(item.ToXmlString(), loadOptions);
		}

		/// <summary>Deserializes an instance of T from XML.</summary>
		/// <param name="xml">The XML string representing a T instance.</param>
		/// <returns>An instance of T that is deserialized from the XML string.</returns>
		/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 01:42:59 GMT"/>
		public static T ToObject<T>(this string xml)
		{
			var deserializer = new DataContractSerializer(typeof(T));

			using (var sr = new StringReader(xml))
			using (var reader = XmlReader.Create(sr))
			{
				return (T)deserializer.ReadObject(reader);
			}
		}

		/// <summary>Converts the collection to a binary array by serializing.</summary>
		/// <typeparam name="T">The type of items in the collection.</typeparam>
		/// <param name="collection">The collection to convert.</param>
		/// <returns>A serialized binary array of the collection.</returns>
		/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 01:42:59 GMT"/>
		public static byte[] ToBinary<T>(this ICollection<T> collection)
		{
			if (collection == null)
				return null;

			var serializer = new DataContractSerializer(typeof(ICollection<T>));

			byte[] buffer;
			using (var ms = new MemoryStream())
			using (var writer = XmlDictionaryWriter.CreateBinaryWriter(ms))
			{
				serializer.WriteObject(writer, collection);
				writer.Flush();
				buffer = ms.ToArray();
			}

			return buffer;
		}

		/// <summary>Deserializes the given XElement to <typeparamref name="T"/></summary>
		/// <param name="xElement">The XElement to be deserialized</param>
		/// <returns><typeparamref name="T"/>or default(<typeparamref name="T"/>) if the xElement was null</returns>
		/// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
		public static T ToObject<T>(this XElement xElement)
		{
			if (xElement == null)
				return default(T);
			DataContractSerializer serializer = new DataContractSerializer(typeof(T));
			T result = (T)serializer.ReadObject(xElement.CreateReader());
			return result;
		}

		/// <summary>Deserializes the given XElement to <typeparamref name="T"/></summary>
		/// <param name="xElement">The XElement to be deserialized</param>
		/// <param name="fakeForInferenceOnly">Not used, but useful when you want the type inference of VS to work for you :)</param>
		/// <returns><typeparamref name="T"/>or default(<typeparamref name="T"/>) if the xElement was null</returns>
		/// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
		public static T ToObject<T>(this XElement xElement, T fakeForInferenceOnly)
		{
			if (xElement == null)
				return default(T);
			DataContractSerializer serializer = new DataContractSerializer(typeof(T));
			T result = (T)serializer.ReadObject(xElement.CreateReader());
			return result;
		}

		/// <summary>Converts the byte array to a collection by deserializing.</summary>
		/// <typeparam name="T">The type of items in the collection.</typeparam>
		/// <param name="buffer">The byte array to convert.</param>
		/// <returns>An instance of <see cref="T:System.Collections.Generic.ICollection`1"/>deserialized from the byte array.</returns>
		/// <created author="laurentiu.macovei" date="Sat, 26 Mar 2011 01:42:59 GMT"/>
		public static ICollection<T> ToCollection<T>(this byte[] buffer)
		{
			if (buffer == null || buffer.Length == 0)
				return null;

			var serializer = new DataContractSerializer(typeof(ICollection<T>));
			object value;

			using (var ms = new MemoryStream(buffer))
			using (var reader = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max))
			{
				ms.Position = 0;
				value = serializer.ReadObject(reader);
			}

			return value as ICollection<T>;
		}

		//#region Business Methods

		///// <summary>Serializes the given object as XmlDocument</summary>
		///// <param name="obj">The xml string to be deserialized</param>
		///// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
		//public static XmlDocument ToXml(this Object obj)
		//{
		//    using (StringWriter sw = new StringWriter())
		//    {
		//        Type t = obj.GetType();
		//        XmlSerializer xs = new XmlSerializer(t);
		//        xs.Serialize(sw, obj);

		//        XmlDocument xd = new XmlDocument();
		//        xd.LoadXml(sw.ToString());

		//        return xd;
		//    }
		//}

		///// <summary>Serializes the given object as xml (string)</summary>
		///// <param name="obj">The xml string to be deserialized</param>
		///// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
		//public static String ToXmlString<T>(this T obj)
		//{
		//    StringBuilder sb = new StringBuilder();
		//    using (XmlTextWriter xw = new XmlTextWriter(new StringWriter(sb)))
		//    {
		//        var sr = new DataContractSerializer(typeof(T));
		//        XmlSerializer xs = new XmlSerializer(typeof(T));
		//        xw.Formatting = Formatting.Indented;
		//        sr.WriteObject(xw, obj);
		//        xs.Serialize(xw, obj);

		//        var r = sb.ToString();
		//        return r;
		//    }
		//}

		///// <summary>Deserializes the given xml as string to <typeparamref name="T"/></summary>
		///// <param name="xmlData">The xml string to be deserialized</param>
		///// <returns><typeparamref name="T"/>or default(<typeparamref name="T"/>) if the xml string was null</returns>
		///// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
		//public static T ToObjectFromXml<T>(this String xmlData)
		//{
		//    XmlSerializer s = new XmlSerializer(typeof(T));
		//    using (StringReader reader = new StringReader(xmlData))
		//    {
		//        Object obj = s.Deserialize(reader);
		//        return (T)obj;
		//    }
		//}

		///// <summary>Deserializes the given XElement to <typeparamref name="T"/></summary>
		///// <param name="xElement">The XElement to be deserialized</param>
		///// <returns><typeparamref name="T"/>or default(<typeparamref name="T"/>) if the xElement was null</returns>
		///// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
		//public static T ToObjectFromXmlElement<T>(this XElement xElement)
		//{
		//    if (xElement == null)
		//        return default(T);
		//    XmlSerializer serializer = new XmlSerializer(typeof(T));
		//    T result = (T)serializer.Deserialize(xElement.CreateReader());
		//    return result;
		//}

		///// <summary>Deserializes the given XElement to <typeparamref name="T"/></summary>
		///// <param name="xElement">The XElement to be deserialized</param>
		///// <param name="fakeForInferenceOnly">Not used, but useful when you want the type inference of VS to work for you :)</param>
		///// <returns><typeparamref name="T"/>or default(<typeparamref name="T"/>) if the xElement was null</returns>
		///// <created author="laurentiu.macovei" date="Thu, 24 Mar 2011 17:42:23 GMT"/>
		//public static T ToObjectFromXmlElement<T>(this XElement xElement, T fakeForInferenceOnly)
		//{
		//    if (xElement == null)
		//        return default(T);
		//    XmlSerializer serializer = new XmlSerializer(typeof(T));
		//    T result = (T)serializer.Deserialize(xElement.CreateReader());
		//    return result;
		//}


		//#endregion Business Methods



	}

}
 
